package face.pay.redis;

import com.alibaba.fastjson.JSON;
import face.pay.AbstractRedis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Created by cai on 2016/3/26.
 */

@Component
public class RedisUtils extends AbstractRedis {

    /**
     * 1 day
     */
    int DEFAULT_TIME_TO_LIVE = 24 * 3600;

    int PLAY_COUNT = 60 * 60;

    int timeToLive = DEFAULT_TIME_TO_LIVE;

    @Autowired
    private RedisTemplate redisTemplate;



    public void set(String key, final Object value, final int expire) {
        if (value instanceof Map) {
            redisTemplate.opsForHash().putAll(key, (Map) value);
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);


        } if(value instanceof String){
            final byte[] rawKey = rawKey(key);
            redisTemplate.execute(new RedisCallback<Object>() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    connection.openPipeline();
                    connection.set(rawKey, redisTemplate.getStringSerializer().serialize(value));
                    connection.expire(rawKey, expire);
                    return connection.closePipeline();
                }
            });
        } else {
            final byte[] rawKey = rawKey(key);
            redisTemplate.execute(new RedisCallback<Object>() {
                @Override
                public Object doInRedis(RedisConnection connection) throws DataAccessException {
                    connection.openPipeline();
                    connection.set(rawKey, redisTemplate.getStringSerializer().serialize(JSON.toJSONString(value)));
                    connection.expire(rawKey, expire);
                    return connection.closePipeline();
                }
            });
        }
    }

    private byte[] rawKey(String key) {
        return redisTemplate.getStringSerializer().serialize(key);
    }


    public void set(String key, Object value) {
        set(key, value,DEFAULT_TIME_TO_LIVE);
    }

    public Object get(final String key) {
        final byte[] rawKey = rawKey(key);


        return redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                DataType keyType = connection.type(rawKey);
                switch (keyType) {
                    case HASH:
                        return redisTemplate.opsForHash().entries(key);
                    default:
                        byte[]  btyes = connection.get(rawKey);
                        return btyes == null ? null : redisTemplate.getStringSerializer().deserialize(btyes);
                }
            }
        });
    }

    private static byte[] objectToBytes(Object obj) {
        byte[] bytes = null;
        try {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ObjectOutputStream sout = new ObjectOutputStream(out);
            sout.writeObject(obj);
            sout.flush();
            bytes = out.toByteArray();
            out.flush();
            return bytes;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }


    public boolean delete(String key) {

        redisTemplate.delete(key);
        return true;
    }

    public void flushAll() {
        redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {
                connection.flushDb();  //清空当前数据库
                return null;
            }
        });
    }

    ///prefix = "helllojava_*";//这个*一定要...
    public int deleteByPrefix(String key) {
        Set<String> keys = redisTemplate.keys(key);
        int count = 0;
        for (String rawKey : keys) {
            redisTemplate.delete(rawKey);
            count++;
        }
        return count;
    }

    public Object incr(String key,final int time){
        final byte[] rawKey = rawKey(key);
        return redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {

                Object count = connection.incr(rawKey);
                connection.expire(rawKey, time);
                return count;
            }
        });
    }

    public Object incrByStep(String key,final long step,final int time){
        final byte[] rawKey = rawKey(key);
        return redisTemplate.execute(new RedisCallback<Object>() {
            @Override
            public Object doInRedis(RedisConnection connection) throws DataAccessException {

                Object count = connection.incrBy(rawKey, step);
                connection.expire(rawKey, time);
                return count;
            }
        });
    }



}
